package logger

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
	"os"
	"strings"
)

var logger *zap.Logger

var sugarLogger *zap.SugaredLogger

func GetLogger() *zap.SugaredLogger {
	if sugarLogger != nil {
		return sugarLogger
	}
	// 设置日志级别
	logLevel := zap.NewAtomicLevelAt(getLogLevel(os.Getenv("LOG_LEVEL")))
	encoder := getEncoder()
	writerSyncer := getLogWriter()
	fileCore := zapcore.NewCore(encoder, writerSyncer, logLevel)
	consoleOutput := zapcore.Lock(os.Stdout)
	consoleCore := zapcore.NewCore(encoder, consoleOutput, logLevel)
	core := zapcore.NewTee(fileCore, consoleCore)
	logger = zap.New(core, zap.AddCaller())
	sugarLogger = logger.Sugar()
	return sugarLogger
}

// 配置日志输出编码
func getEncoder() zapcore.Encoder {
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",                         // 时间字段的键名
		LevelKey:       "level",                        // 日志级别字段的键名
		NameKey:        "logger",                       // 记录器名称的键名
		CallerKey:      "caller",                       // 调用者信息的键名
		MessageKey:     "stacktrace",                   // 消息内容的键名
		EncodeTime:     zapcore.ISO8601TimeEncoder,     // 时间格式为 ISO8601
		EncodeDuration: zapcore.SecondsDurationEncoder, // 持续时间以秒为单位
		EncodeCaller:   zapcore.ShortCallerEncoder,     // 短格式的调用者信息（文件:行号）
		EncodeLevel:    zapcore.CapitalLevelEncoder,    // 大写的级别名称（INFO, ERROR等）
	}
	return zapcore.NewConsoleEncoder(encoderConfig)
}

// 日志写入到文件中
func getLogWriter() zapcore.WriteSyncer {
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "logs/app.log", // 日志文件路径
		MaxSize:    10,             // 单个文件最大10MB
		MaxBackups: 5,              // 保留5个备份
		MaxAge:     30,             // 保留30天
		Compress:   false,          // 不压缩旧日志
	}
	return zapcore.AddSync(lumberJackLogger)
}

// 获取日志级别
func getLogLevel(level string) zapcore.Level {
	// DEBUG > INFO > WARN > ERROR > FATAL > PANIC
	switch strings.ToUpper(level) {
	case "DEBUG":
		return zapcore.DebugLevel
	case "WARN":
		return zapcore.WarnLevel
	case "ERROR":
		return zapcore.ErrorLevel
	default:
		return zapcore.InfoLevel
	}
}
